#include <trap.h>
#include <stdio.h>

static void trap_dipatch(struct trapframe *tf) {
    // scause的最高位是1，说明trap是由中断引起的
    // scause的最高位是0，说明trap是异常引起的
    if ((int64_t)tf->scause < 0) {
        // interrupts
        interrupt_handler(tf);
    } else {
        // exceptions
        exception_handler(tf);
    }
}

void trap(struct trapframe *tf) {
    trap_dipatch(tf);
    // if (++ticks % TICK_NUM == 0) {
    //     printf("cause: %x\n", tf->scause);
    // }
    // clock_set_next_event();
    // print_trapframe(tf);
}

/* set trap vec */
void idt_init(void) {
    extern void __alltraps(void);
    //约定：若中断前处于S态，sscratch为0
    //若中断前处于U态，sscratch存储内核栈地址
    //那么之后就可以通过sscratch的数值判断是内核态产生的中断还是用户态产生的中断
    //我们现在是内核态所以给sscratch置零
    write_csr(sscratch, 0);
    write_csr(stvec, &__alltraps);
}

void interrupt_handler(struct trapframe *tf) {
    int64_t cause = (tf->scause << 1) >> 1;
    switch (cause) {
        case IRQ_U_SOFT:
            printf("User software interrupt\n");
            break;
        case IRQ_S_SOFT:
            printf("Supervisor software interrupt\n");
            break;
        case IRQ_H_SOFT:
            printf("Hypervisor software interrupt\n");
            break;
        case IRQ_M_SOFT:
            printf("Machine software interrupt\n");
            break;
        case IRQ_U_TIMER:
            printf("User software interrupt\n");
            break;
        case IRQ_S_TIMER:
            //时钟中断
            clock_set_next_event();
            if (++ticks % TICK_NUM == 0) {
                printf("intr: %d\n", ticks);
            }
            break;
        case IRQ_H_TIMER:
            printf("Hypervisor software interrupt\n");
            break;
        case IRQ_M_TIMER:
            printf("Machine software interrupt\n");
            break;
        case IRQ_U_EXT:
            printf("User software interrupt\n");
            break;
        case IRQ_S_EXT:
            printf("Supervisor external interrupt\n");
            break;
        case IRQ_H_EXT:
            printf("Hypervisor software interrupt\n");
            break;
        case IRQ_M_EXT:
            printf("Machine software interrupt\n");
            break;
        default:
            print_trapframe(tf);
            break;
    }
}

void exception_handler(struct trapframe *tf) {
    switch (tf->scause) {
        case CAUSE_MISALIGNED_FETCH:
            break;
        case CAUSE_FAULT_FETCH:
            break;
        case CAUSE_ILLEGAL_INSTRUCTION:
            break;
        case CAUSE_BREAKPOINT:
            break;
        case CAUSE_MISALIGNED_LOAD:
            break;
        case CAUSE_FAULT_LOAD:
            break;
        case CAUSE_MISALIGNED_STORE:
            break;
        case CAUSE_FAULT_STORE:
            break;
        case CAUSE_USER_ECALL:
            break;
        case CAUSE_SUPERVISOR_ECALL:
            break;
        case CAUSE_HYPERVISOR_ECALL:
            break;
        case CAUSE_MACHINE_ECALL:
            break;
        default:
            print_trapframe(tf);
            break;
    }
}

void print_regs(struct regs *gpr) {
    printf("  zero     0x%x\n", gpr->zero);
    printf("  ra       0x%x\n", gpr->ra);
    printf("  sp       0x%x\n", gpr->sp);
    printf("  gp       0x%x\n", gpr->gp);
    printf("  tp       0x%x\n", gpr->tp);
    printf("  t0       0x%x\n", gpr->t0);
    printf("  t1       0x%x\n", gpr->t1);
    printf("  t2       0x%x\n", gpr->t2);
    printf("  s0       0x%x\n", gpr->s0);
    printf("  s1       0x%x\n", gpr->s1);
    printf("  a0       0x%x\n", gpr->a0);
    printf("  a1       0x%x\n", gpr->a1);
    printf("  a2       0x%x\n", gpr->a2);
    printf("  a3       0x%x\n", gpr->a3);
    printf("  a4       0x%x\n", gpr->a4);
    printf("  a5       0x%x\n", gpr->a5);
    printf("  a6       0x%x\n", gpr->a6);
    printf("  a7       0x%x\n", gpr->a7);
    printf("  s2       0x%x\n", gpr->s2);
    printf("  s3       0x%x\n", gpr->s3);
    printf("  s4       0x%x\n", gpr->s4);
    printf("  s5       0x%x\n", gpr->s5);
    printf("  s6       0x%x\n", gpr->s6);
    printf("  s7       0x%x\n", gpr->s7);
    printf("  s8       0x%x\n", gpr->s8);
    printf("  s9       0x%x\n", gpr->s9);
    printf("  s10      0x%x\n", gpr->s10);
    printf("  s11      0x%x\n", gpr->s11);
    printf("  t3       0x%x\n", gpr->t3);
    printf("  t4       0x%x\n", gpr->t4);
    printf("  t5       0x%x\n", gpr->t5);
    printf("  t6       0x%x\n", gpr->t6);
}

void print_trapframe(struct trapframe *tf) {
    printf("trapframe at %p\n", tf);
    print_regs(&tf->gpr);
    printf("  status   0x%x\n", tf->sstatus);
    printf("  epc      0x%x\n", tf->sepc);
    printf("  badvaddr 0x%x\n", tf->sbadvaddr);
    printf("  cause    0x%x\n", tf->scause);
}